import React, { useCallback, useEffect, useRef, useState } from 'react'
import { Input } from 'antd';
import bigDecimal from 'js-big-decimal';
import { convertToNumber, isNumber, setCaretPosition } from './util'

const convert2PercentInfo = (valueStr, needDecimal, decimalPlaces, thousandsSeparator) => {
    const value = isNumber(valueStr) ? +valueStr : valueStr;
    const inputStr = isNumber(valueStr) ? +bigDecimal.multiply(valueStr, 100) : valueStr;
    const rel = convertToNumber(inputStr, needDecimal, decimalPlaces, '');
    const inputValue = rel ? +rel : rel;
    const formatValue = rel ? convertToNumber(rel, needDecimal, decimalPlaces, thousandsSeparator) : rel;

    return {
        value,
        inputValue,
        formatValue
    };
};

const convert2PercentInfoByInput = (inputStr, needDecimal, decimalPlaces, thousandsSeparator) => {
    const rel = convertToNumber(inputStr, needDecimal, decimalPlaces, '');

    if (rel === '-') {
        return !needDecimal
            ? { value: rel, inputValue: rel, formatValue: rel }
            : { value: null, inputValue: '', formatValue: '' };
    }

    const inputValue = rel ? +rel : rel;
    const formatValue = convertToNumber(rel, needDecimal, decimalPlaces, thousandsSeparator);
    const value = isNumber(inputValue) ? +bigDecimal.divide(inputValue, 100) : inputValue;

    return {
        value,
        inputValue,
        formatValue
    };
};

const INPUT_TYPE = {
    KEY_PRESS: 'keyPress',
    COMPOSITION: 'composition'
};

/**
 * 百分比输入控件
 * @param value 数值
 * @param onChange
 * @param decimalPlaces 小数位数
 * @param thousandsSeparator 千位分隔符
 * @param { 'right' | 'left' |'center' } align
 * @param otherProps 其余antd Input 属性
 * @param ref
 * @returns {JSX.Element}
 * @constructor
 */
const PercentInput = ({
    value,
    onChange,
    decimalPlaces = '',
    thousandsSeparator = '',
    align = 'right',
    nonNegative,
    ...otherProps
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}, ref) => {
    const inputRef = useRef(null);
    const initValue = convert2PercentInfo(value, true, decimalPlaces, thousandsSeparator);
    const [valueInfo, setValueInfo] = useState(initValue);
    const beforeLengthRef = useRef(null);
    const numberStepRef = useRef(0);
    const positionRef = useRef(null);
    const inputTypeRef = useRef(null);

    const onKeyDown = e => {
        const { value: inputVal/* 文本框的值 */, selectionStart/* 光标起始位置 */ } = e.target;
        // 光标前的字符串
        const beforeCaretStr = String(inputVal).substr(0, selectionStart);
        // 去除千分符的字符串长度
        const beforeLength = thousandsSeparator
            ? beforeCaretStr.replace(new RegExp(thousandsSeparator, 'g'), '').length
            : beforeCaretStr.length;

        beforeLengthRef.current = beforeLength;
        numberStepRef.current = e.which === 8 ? -1 : 0;
    };

    const onKeyPress = e => {
        if (nonNegative && e.key === '-') {
            e.preventDefault();
        }
        numberStepRef.current = 1;
        inputTypeRef.current = INPUT_TYPE.KEY_PRESS;
    };

    const onCompositionStart = () => {
        numberStepRef.current = 1;
        inputTypeRef.current = INPUT_TYPE.COMPOSITION;
    };

    const onInputChange = useCallback((inputElement, inputValue) => {
        const newValueInfo = convert2PercentInfoByInput(inputValue, false, decimalPlaces, thousandsSeparator);
        setValueInfo(newValueInfo);
        onChange(newValueInfo.value);
        positionRef.current = {
            inputElement,
            formatValue: newValueInfo.formatValue,
            beforeLength: beforeLengthRef.current + numberStepRef.current,
            thousandsSeparator
        };
    });

    const onSelect = () => {
        if (positionRef.current) {
            const positionInfo = positionRef.current;
            setCaretPosition(
                positionInfo.inputElement,
                positionInfo.formatValue,
                positionInfo.beforeLength,
                thousandsSeparator
            );
            positionRef.current = null;
        }
    };

    const onBlur = e => {
        if (otherProps.onBlur) {
            otherProps.onBlur(e);
        }
        // 失焦时自动加上小数位
        const newValueInfo = convert2PercentInfoByInput(e.target.value, true, decimalPlaces, thousandsSeparator);
        setValueInfo(newValueInfo);
        onChange(newValueInfo.value);
    };

    const style = {
        ...otherProps.style,
        textAlign: align
    };

    // 当传进来的值变更时，重新设置格式化的值
    useEffect(() => {
        const newValue = convert2PercentInfo(value, true, decimalPlaces, thousandsSeparator, nonNegative);
        if (newValue.value !== valueInfo.value && (valueInfo.value !== '-' || (valueInfo.value === '-' && nonNegative))) {
            setValueInfo(newValue);
            onChange(newValue.value);
        }
    }, [value]);

    useEffect(() => {
        const newValue = convert2PercentInfo(value, true, decimalPlaces, thousandsSeparator, nonNegative);

        if (newValue.value === valueInfo.value && newValue.formatValue !== valueInfo.formatValue) {
            setValueInfo(newValue);
        }
    }, [decimalPlaces, thousandsSeparator, nonNegative]);

    return (
        <Input
            {...otherProps}
            value={valueInfo.formatValue}
            onKeyDown={onKeyDown}
            onKeyPress={onKeyPress}
            onCompositionStart={onCompositionStart}
            onChange={e => {
                const { nativeEvent } = e;

                if (
                    inputTypeRef.current !== INPUT_TYPE.COMPOSITION ||
                    // 中方输入法时，避免在类似"123"再输入4时会出现重复的4
                    (inputTypeRef.current === INPUT_TYPE.COMPOSITION && nativeEvent?.inputType !== 'insertText')
                ) {
                    onInputChange(e.target, e.target.value, { ...e.nativeEvent });
                }
            }}
            onSelect={onSelect}
            onBlur={onBlur}
            style={style}
            suffix="%"
            maxLength={12}
            ref={inputRef}
        />
    );
};

export default PercentInput;
